// 通过两点经纬度计算距离（KM）
export function getDistance(lat1, lng1, lat2, lng2) {
  // lat1：用户的纬度 lng1：用户的经度 lat2：商家的纬度 lng2：商家的经度
  const Rad = function (d) {
    return d * Math.PI / 180.0;
  }
  var radLat1 = Rad(lat1);
  var radLat2 = Rad(lat2);
  var a = radLat1 - radLat2;
  var b = Rad(lng1) - Rad(lng2);
  var s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
  s = s * 6378.137;
  s = Math.round(s * 10000) / 10000 * 1000;
  s = s.toFixed(2) // 保留两位小数
  console.log('经纬度计算的相差距离: ', s)
  return s
}

export function formatTimeDate(date, fmt) {
  // date 为时间（通过 new Date() 转换了的）， fmt 为时间格式（如：yyyy-MM-dd hh:mm）
  if (/(y+)/.test(fmt)) {
    // 例如 fmt 格式为 'yyyy-MM-dd hh:mm' , 则 /(y+)/ 匹配 yyyy 年份
    fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
    // RegExp.$1 为匹配到的第一个值，此处为 yyyy
    // 同时，获取时间的年份 替换 yyyy，如果 fmt 的格式为 'yy-MM-dd hh:mm',则只取年份的后两位进行替换
    // date.getFullYear() + '' 为将获取的时间的年份转换为字符串
    // substr() 方法可在字符串中抽取从 start 下标开始的指定数目的字符
  }
  let o = {
    'M+': date.getMonth() + 1,
    'd+': date.getDate(),
    'h+': date.getHours(),
    'm+': date.getMinutes(),
    's+': date.getSeconds()
  }
  // for...in 语句用于遍历数组或者对象的属性（对数组或者对象的属性进行循环操作）
  for (let k in o) {
    if (new RegExp(`(${k})`).test(fmt)) {
      // 匹配对应的正则，即 /(MM)/  /(dd)/  /(hh)/  /(ss)/
      let str = o[k] + '' // 将匹配对应的时间转换为字符串
      fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str))
      // 替换格式中对应的 MM  dd  hh  ss
      // RegExp.$1.length === 1 判断匹配的fmt格式的值的长度(即判断 MM dd hh ss,是否为M d h s)是否为 1
      // 例如 'yyyy-M-dd hh:mm'
      // 如果是则直接返回对应的时间，如果不是，则在前面添加 '0'
    }
  }
  return fmt
}

function padLeftZero(str) {
  // 示例，str 为 '12'，则从字符串 '0012' 中抽取从下标2开始到结束的字符串，包括下标2
  return ('00' + str).substr(str.length)
}

// 格式化过去的时间
export function formatPassTime(startTime) {
  var currentTime = Date.parse(new Date()),
    time = currentTime - startTime,
    day = parseInt(time / (1000 * 60 * 60 * 24)),
    hour = parseInt(time / (1000 * 60 * 60)),
    min = parseInt(time / (1000 * 60)),
    month = parseInt(day / 30),
    year = parseInt(month / 12);
  if (year) return year + "年前"
  if (month) return month + "个月前"
  if (day) return day + "天前"
  if (hour) return hour + "小时前"
  if (min) return min + "分钟前"
  else return '刚刚'
}

// 防抖
// >>> 非立即执行:，如果在一个事件触发的n秒内又触发了这个事件，那就以新的事件的时间为准，n 秒后才执行
// >>> 立即执行：不希望非要等到事件停止触发后才执行，希望立刻执行函数，然后等到停止触发 n 秒后，才可以重新触发执行
// 参数：
// >>> fn: 回调行数
// >>> wait: 等待时间
// >>> immediate: 是否立即执行。true：立即执行， false：非立即执行
// 使用场景
// >>> search搜索联想，用户在不断输入值时，用防抖来节约请求资源。
// >>> window触发resize的时候，不断的调整浏览器窗口大小会不断的触发这个事件，用防抖来让其只触发一次
export function debounce(fn, wait, immediate) {
  let timeout, result;
  let debounced = function () {
    let context = this;
    let args = arguments;
    if (timeout) {
      clearTimeout(timeout);
    }
    let callNow = !timeout;
    if (immediate) {
      // 已经执行过，不再执行
      timeout = setTimeout(function () {
        timeout = null;
      }, wait);
      if (callNow) {
        result = fn.apply(context, args);
      }
    } else {
      timeout = setTimeout(function () {
        result = fn.apply(context, args);
      }, wait);
    }
  };
  debounced.cancel = function () {
    clearTimeout(timeout);
    timeout = null;
  };
  return debounced;
}

// 节流
// >>> 非立即执行: 过了n秒后我们再执行
// >>> 立即执行：当触发事件的时候，取出当前的时间戳，然后减去之前的时间戳(最一开始值设为 0)，如果大于设置的时间周期，就执行函数，然后更新时间戳为当前的时间戳，如果小于，就不执行
// 参数
// >>> fn：回调函数
// >>> wait：等待时间
// >>> options：Object。{immediate：Boolean， last： Boolean}
// >>> -- immediate: 是否立即执行。true：立即执行， false：非立即执行
// >>> -- last: 是否禁用停止触发的回调。true：不禁用， false：禁用
// 使用场景：
// >>> 鼠标不断点击触发，mousedown(单位时间内只触发一次)
// >>> 监听滚动事件，比如是否滑到底部自动加载更多，用throttle来判断
export function throttle(fn, wait, options) {
  let timeout, remaining, context, args;
  let previous = 0;
  // timeout等于null,代表定时器已经完成
  // 如果没有传 options 默认为空 
  if (!options) {
    options = {}; // 虽然没有声明 options, 相当于window.options={}
  }
  let later = function () {
    // previous = +new Date(); // +new Date() 等同于:new Date().getTime()
    previous = options.immediate == false ? 0 : new Date().getTime();
    timeout = null;
    fn.apply(context, args);
    if (!timeout) context = args = null;
    // console.log("最后执行的");
  };
  let throttled = function () {
    context = this;
    args = arguments;
    let now = new Date().getTime(); // +new Date() 等同于:new Date().getTime()
    if (!previous && options.immediate === false) {
      previous = now;
    }
    // 下次触发 func 剩余的时间
    remaining = wait - (now - previous);
    // 代表我这个定时器执行完了 那么就执行n秒后(比如：3~6秒)的事件操作
    // 如果没有剩余的时间了
    if (remaining <= 0) {
      if (timeout) {
        clearTimeout(timeout);
        timeout = null;
      }
      previous = now;
      // 立即执行
      fn.apply(context, args);
      if (!timeout) context = args = null;
    } else if (!timeout && options.last !== false) {
      timeout = setTimeout(later, remaining);
    }
  };
  throttled.cancel = function () {
    clearTimeout(timeout);
    timeout = null;
    previous = 0;
  };
  return throttled;
}